package utils

import (
	"errors"
	"github.com/golang-jwt/jwt/v5"
	"github.com/spf13/viper"
	"strconv"
	"time"
)

type MyClaims struct {
	LoginName string
	UserId    uint
	RoleIds   []uint `json:"role_id"`
	jwt.RegisteredClaims
}

var key = viper.GetString("jwt.key")

// MyCustomClaims 加密生成token
func MyCustomClaims(LoginName string, userID uint, roleIds []uint) (token string, err error) {
	// Create a new Myclaims struct with the given username, userID, and roleID
	c := MyClaims{
		LoginName: LoginName,
		UserId:    userID,
		RoleIds:   roleIds,
		RegisteredClaims: jwt.RegisteredClaims{
			Issuer:    "GIn_admin_server",                                                                     //颁发者，表示生成Token的实体。
			Subject:   "tang",                                                                                 //主题，表示Token的主题。
			Audience:  jwt.ClaimStrings{"Android_APP", "IOS_APP", "WEB"},                                      //观众，表示Token的接收者。
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * viper.GetDuration("jwt.tokenExpire"))), //过期时间，表示Token的有效期截止时间。应该是一个以秒为单位的时间戳。
			//NotBefore: jwt.NewNumericDate(time.Now().Add(time.Second)), //生效时间，表示Token在这个时间之前是无效的。应该是一个以秒为单位的时间戳。 不配置默认立即生效
			IssuedAt: jwt.NewNumericDate(time.Now()),                           //签发时间，表示Token的签发时间。应该是一个以秒为单位的时间戳。
			ID:       LoginName + strconv.FormatInt(time.Now().UnixNano(), 10), //Token的JWT ID 用用户名+纳米时间戳来表示，每次请求都是唯一的。 后期可以用id来做黑名单

		},
	}
	token, err = jwt.NewWithClaims(jwt.SigningMethodHS256, c).SignedString([]byte(key))
	return token, err
}

// ParseTokenHs256 解密token
func ParseTokenHs256(tokenString string) (*MyClaims, error) {
	//解析token字符串，并使用自定义的Myclaims类型进行验证
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(key), nil //返回签名密钥
	})
	if err != nil {
		return nil, err
	}

	//检查token是否有效
	if !token.Valid {
		return nil, errors.New("身份验证失败,token无效")
	}

	//断言成为Myclaims类型
	claims, ok := token.Claims.(*MyClaims)
	if !ok {
		return nil, errors.New("无效的token类型")
	}
	return claims, nil
}
